#ifndef _M_BUFFER_H__
#define _M_BUFFER_H__

#include <iostream>
#include <vector>
#include <cassert>
#include <cstring>
#include "../log/logger.hpp"
#include "../log/log.hpp"
#include "../log/err.hpp"

#define BUFFER_DEFAULT_SIZE 1024
class Buffer
{
public:
    Buffer()
    :_buffer(BUFFER_DEFAULT_SIZE),_reader_idx(0),_writer_idx(0)
    {}
    ~Buffer()
    {
        _buffer.clear();
    }
    char* Begin() { return &*_buffer.begin(); }
    //获取当前写入起始位置
    char* WritePosition() { return Begin() + _writer_idx; }
    //获取当前读取起始位置
    char* ReadPosition() { return Begin() + _reader_idx; }
    //获取缓冲区末尾空闲空间
    uint64_t TailIdleSize() { return _buffer.size() - _writer_idx; }
    //获取缓冲区起始空闲空间
    uint64_t HeadIdleSize() { return _reader_idx; }
    //获取可读数据大小
    uint64_t ReadAblesSize() { return _writer_idx - _reader_idx; }
    //将读偏移向后移动
    void MoveReadOffset(uint64_t len)
    {
        if(len == 0) return;
        //必须保证有可读的数据大小
        assert(len <= ReadAblesSize());
        _reader_idx += len;
    }
    //将写偏移向后移动
    void MoveWriteOffset(uint64_t len)
    {
        assert(len <= TailIdleSize());
        _writer_idx += len;
    }
    //确保可写空间足够
    void EnsureWriteSpace(uint64_t len)
    {
        //末尾空闲空间
        if(TailIdleSize() >= len) 
            return;
        //再加上前言空闲空间
        if(len <= TailIdleSize() + HeadIdleSize())
        {
            //把数据移到起始位置
            uint64_t rsz = ReadAblesSize();
            //std::copy(start, end, std::back_inserter(container));
            std::copy(ReadPosition(),ReadPosition() + rsz,Begin());
            _reader_idx = 0;
            _writer_idx = rsz;
        }
        else//扩容
        {
            //DBG_LOG("RESIZE %ld",_writer_idx + len);
            logMessage(DEBUG,"RESIZE %ld",_writer_idx + len);
            _buffer.resize(_writer_idx + len);
        }
        
    }
    //写入数据
    void Write(const void* data,uint64_t len)
    {
        //1.保证空间大小,拷贝数据
        if(len == 0) return;
        EnsureWriteSpace(len);
        const char* d = (const char*)data;
        std::copy(d,d+len,WritePosition());
    }
    //写入数据并后移
    void WriteandPush(const void* data,uint64_t len)
    {
        Write(data,len);
        MoveWriteOffset(len);
    }
    //写入string数据
    void WriteString(const std::string& data)
    {
        return Write(data.c_str(),data.size());
    }
    //写入string并后移
    void WriteStringAndPush(const std::string& data)
    {
        WriteString(data);
        MoveWriteOffset(data.size());
    }
    //写入buffer数据
    void WriteBuffer(Buffer& data)
    {
        return Write(data.ReadPosition(),data.ReadAblesSize());
    }
    //写入buffer并后移
    void WriteBufferAndPush(Buffer& data)
    {
        WriteBuffer(data);
        MoveWriteOffset(data.ReadAblesSize());
    }
    //读取数据
    void Read(void* buf,uint64_t len)
    {
        assert(len <= ReadAblesSize());
        std::copy(ReadPosition(),ReadPosition() + len,(char*)buf);
    }
    //读取数据并后移
    void ReadAndPop(void* buf,uint64_t len)
    {
        Read(buf,len);
        MoveReadOffset(len);
    }
    //读取string数据
    std::string ReadString(uint64_t len)
    {
        assert(len <= ReadAblesSize());
        std::string str;
        str.resize(len);
        Read(&str[0],len);
        return str;
    }
    //读取string并后移
    std::string ReadStringAndPop(uint64_t len)
    {
        assert(len <= ReadAblesSize());
        std::string str = ReadString(len);
        MoveReadOffset(len);
        return str;
    }
    //获取换行符
    char* FindCRLF()
    {
        char* res = (char*)memchr(ReadPosition(),'\n',ReadAblesSize());
        return res;
    }
    //获取一行数据
    std::string GetLine()
    {
        char* pos = FindCRLF();
        if(pos == nullptr)
            return "";
        //+1 是为了把\n也取出来
        return ReadString(pos - ReadPosition() + 1);
    }
    //获取一行数据并后移
    std::string GetLineAndPop()
    {
        std::string str = GetLine();
        MoveReadOffset(str.size());
        return str;
    }
    //清空缓冲区
    void Clear()
    {
        _writer_idx = 0;
        _reader_idx = 0;
    }
private:
    std::vector<char> _buffer;
    uint64_t _reader_idx;
    uint64_t _writer_idx;
};

#endif